home *** CD-ROM | disk | FTP | other *** search
- /*
- * load_mtm.c - Loads Multitracker modules.
- *
- * (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
- */
-
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <sys/soundcard.h>
- #include <sys/ultrasound.h>
- #include <limits.h>
- #include <string.h>
- #include <ctype.h>
-
- #include "mod.h"
-
- /* External global variables */
-
- SEQ_DECLAREBUF();
- extern int seqfd, gus_dev;
-
- extern struct mod_info M;
- extern struct options opt;
-
- extern char quit;
-
- extern char effect_used[NR_EFX];
-
- /* Local functions */
-
- static int process_header(int);
- static int read_patterndata(int);
- static void fix_effect(unsigned char *, unsigned char *);
-
- /* Defines and variables used while loading module */
-
- #define MTM_HEADER_SIZE 66
- #define MTM_SAMPLEINFO_SIZE 37
-
- #define MTM_MAGIC 0
- #define MTM_VERSION 3
- #define MTM_NAME 4
- #define MTM_TRACKS 24
- #define MTM_PATTERNS 26
- #define MTM_SONGLENGTH 27
- #define MTM_COMMENT_LEN 28
- #define MTM_NOS 30
- #define MTM_UNUSEDATTR 31
- #define MTM_BPT 32
- #define MTM_PLAYEDTRACKS 33
- #define MTM_PANPOS 34
-
- #define MTM_S_NAME 0
- #define MTM_S_LEN 22
- #define MTM_S_LOOPSTART 26
- #define MTM_S_LOOPEND 30
- #define MTM_S_FINETUNE 34
- #define MTM_S_VOLUME 35
- #define MTM_S_ATTR 36
-
- #define MTM_FLAG_BITS_16 1
-
- static int expected_length, tracks, commentlen;
-
- int load_mtm(int fd)
- {
- char tmpbuf[80];
-
- int i, diff, fatalerr;
-
- print_status("Loading MTM");
- M.nr_tracks=0;
-
- if(!process_header(fd))
- return 0;
-
- if(!read_patterndata(fd)) {
- info("Unable to read patterndata.\n");
- return 0;
- }
-
- ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev);
-
- info("\nUploading instruments to GUS...\n");
-
- fatalerr=0;
-
- for(i=1; i <= M.nr_samples; ++i) {
- if(M.sample[i].length > 4) { /* Only load non-silent samples */
- if(!read_and_upload_sample(fd, i)) {
- fatalerr=1;
- break;
- }
- }
- else { /* Skip sample */
- if(lseek(fd, M.sample[i].length, SEEK_CUR) == -1){
- fatalerr=1;
- break;
- }
- }
- if(quit == QUIT_SIGNAL) /* Bail out if we got QUIT_SIGNAL */
- return 0;
- }
-
- if(fatalerr) {
- diff=expected_length-lseek(fd, 0, SEEK_CUR);
- sprintf(tmpbuf, "File %d bytes short", diff);
- print_status(tmpbuf);
- info("\nShort file (%d bytes missing).\n",0);
- sleep(1);
- return 0;
- }
-
- /* Check if filelength was as expected. This is done with two
- * statements to make sure we don't move the filepointer to the
- * end before checking current position.
- */
-
- diff=-lseek(fd, 0, SEEK_CUR);
- diff+=lseek(fd, 0, SEEK_END);
-
- if(diff && opt.verbose) {
- warning("\nFound %d garbagebytes after samples. Ignoring.\n", diff);
- }
-
- print_songname(M.name);
- print_samples(1);
- print_songinfo(M.nr_voices, M.nr_samples, "MTM", expected_length,
- M.songlength, M.nr_patterns);
- return 1;
- }
-
-
- static int process_header(int fd)
- {
- unsigned char buf[MTM_HEADER_SIZE];
- int tmp, i;
- struct sample_info *s;
-
- if(read(fd, buf, MTM_HEADER_SIZE) != MTM_HEADER_SIZE) {
- info("Unable to read header from file.\n");
- return 0;
- }
-
- expected_length=MTM_HEADER_SIZE; /* Start counting expected filesize */
-
- if(strncmp("MTM", &buf[MTM_MAGIC], 3)) {
- info("Not a Multitracker module.\n");
- return 0;
- }
-
- info("Format version %d.%d\n", (buf[MTM_VERSION]>>4)&0x0f,
- buf[MTM_VERSION]&0x0f);
-
- /* Copy songname and strip trailing spaces */
- strncpy(M.name, &buf[MTM_NAME], 20);
- M.name[20]=0;
- fix_string(M.name);
-
- tracks=*(unsigned short *)&buf[MTM_TRACKS];
- M.nr_patterns=buf[MTM_PATTERNS]+1;
- M.songlength=buf[MTM_SONGLENGTH]+1;
- commentlen=*(unsigned short *)&buf[MTM_COMMENT_LEN];
- M.nr_samples=buf[MTM_NOS];
-
- info("Tracks saved: %d\n", tracks);
-
- if(!M.nr_samples || M.nr_samples > 127) {
- info("Invalid number of samples in module.\n");
- return 0;
- }
-
- if(M.nr_patterns > 127) {
- info("Invalid number of patterns.\n");
- return 0;
- }
-
- if(buf[MTM_BPT] != 64) {
- info("Beats (lines) per track: %d (!=64!).\n", buf[MTM_BPT]);
- return 0;
- }
-
- M.sample=(struct sample_info *)malloc((1+M.nr_samples)*
- sizeof(struct sample_info));
-
- expected_length+=M.nr_samples*MTM_SAMPLEINFO_SIZE;
- print_sample_info_header();
-
- for(i=1; i <= M.nr_samples; ++i) {
- if(read(fd, buf, MTM_SAMPLEINFO_SIZE) != MTM_SAMPLEINFO_SIZE) {
- info("Unable to read sampleheader (%d).\n", i);
- return 0;
- }
-
- s=&M.sample[i];
- s->valid=0; /* Valid isn't set to TRUE until it's
- * sampledata has been read.
- */
- strncpy(s->name, &buf[MTM_S_NAME], 22);
- s->name[22]=0;
- fix_string(s->name);
-
- s->length=*(unsigned long *)&buf[MTM_S_LEN];
- s->repeat_start=*(unsigned long *)&buf[MTM_S_LOOPSTART];
- s->repeat_end=*(unsigned long *)&buf[MTM_S_LOOPEND];
- s->finetune=buf[MTM_S_FINETUNE];
- s->volume=buf[MTM_S_VOLUME];
-
- s->c2freq=-1; /* Use PAL/NTSC */
-
- if(buf[MTM_S_ATTR]&MTM_FLAG_BITS_16)
- s->bits_16=1;
- else
- s->bits_16=0;
-
- if(s->repeat_end > s->repeat_start+4)
- s->looped=LOOP_FORWARD;
- else
- s->looped=0;
-
- s->unsigned_data=1;
-
- s->repeat_start=MIN(MAX(0, s->repeat_start), s->length-2);
-
- /* Is this one including/excluding the last sample? */
- s->repeat_end=MIN(MAX(0, s->repeat_end), s->length-2);
-
- expected_length+=s->length;
-
- print_sample_info(i);
- }
-
- if(read(fd, M.patterntable, 128) != 128) {
- info("Unable to load patterntable.\n");
- return 0;
- }
- expected_length+=128;
-
- for(i=0; i < 128; ++i)
- if(M.patterntable[i] >= M.nr_patterns)
- break;
-
- M.songlength=MIN(i, M.songlength);
-
- for(tmp=0; tmp < MAX_VOICES; ++tmp)
- M.panning[tmp]=get_voice_balance(tmp);
-
- M.restartpos=0;
- M.volrange=64;
-
- info("\nSamples: %d Patterns: %d Songlength: %d\n",
- M.nr_samples, M.nr_patterns, M.songlength);
-
- return 1;
- }
-
-
- static int read_patterndata(int fd)
- {
- int track_mapping[128*32]; /* Maximum number of tracks */
- unsigned char buf[2*32*128]; /* Max track seq. data */
- char used_voices[32];
- unsigned char *b;
- unsigned short effect;
- struct event *e;
- int t, p, l, v, tmp;
- struct event events[64];
-
- for(v=0; v < NR_EFX; ++v)
- effect_used[v]=0;
-
- /* Allocate for worst case (no identical tracks) */
- M.tracks=(struct event **)malloc(tracks*sizeof(struct event *));
-
- /* Add the empty track */
- bzero((void *)events, sizeof(struct event)*64);
- track_mapping[0]=get_track_idx(events);
-
- for(t=1; t <= tracks; ++t) {
- if(read(fd, buf, 64*3) != 64*3)
- return 0;
- expected_length+=64*3;
-
- b=buf;
- for(l=0; l < 64; ++l, b+=3) {
- e=&events[l];
- /* 2*12 because X-2 => X-4 */
- e->note=(b[0]&0xfc ? ((b[0]&0xfc)>>2)+BASE_NOTE+2*12 : 0);
- e->sample=((b[0]&0x03)<<4)|((b[1]>>4)&0x0f);
- effect=b[1]&0x0f;
-
- if(effect != 0x0e)
- e->arg=b[2];
- else {
- effect=0x10|((b[2]>>4)&0x0f);
- e->arg=b[2]&0x0f;
- }
- e->effect=effect;
- fix_effect(&e->effect, &e->arg);
-
- if(e->effect ||e->arg)
- effect_used[e->effect]=1;
-
- e->effect2=e->arg2=0;
- }
- track_mapping[t]=get_track_idx(events);
- }
- print_used_effects();
-
- if(read(fd, buf, M.nr_patterns*32*2) != M.nr_patterns*32*2)
- return 0;
- expected_length+=M.nr_patterns*32*2;
-
- bzero((void *)used_voices, 32);
- for(p=0; p < M.nr_patterns; ++p)
- for(v=0; v < 32; ++v)
- if(track_mapping[*(unsigned short *)&buf[(p*32+v)*2]])
- used_voices[v]=1;
-
- for(v=31; v >= 0 && !used_voices[v]; --v)
- ;
- M.nr_voices=v+1;
-
- if(!M.nr_voices) {
- info("Song empty (no tracks used).\n");
- return 0;
- }
- info("Used voices: %d\n", M.nr_voices);
-
- for(v=0; v < M.nr_voices; ++v)
- M.track_idx[v]=(int *)malloc(M.nr_patterns*sizeof(int));
-
- for(p=0; p < M.nr_patterns; ++p) {
- for(v=0; v < M.nr_voices; ++v) {
- tmp=*(unsigned short *)&buf[(p*32+v)*2];
- if(tmp > tracks) {
- info("Illegal track specified (%d).\n", tmp);
- return 0;
- }
- else {
- M.track_idx[v][p]=track_mapping[tmp];
- }
- }
- }
-
- /* C-0 through D#5 (before "transposing" 2 octaves) */
- opt.low_note=BASE_NOTE+2*12;
- opt.high_note=BASE_NOTE+7*12+4;
-
- if(commentlen) {
- M.songtext=(void *)malloc(commentlen+1);
- if(read(fd, M.songtext, commentlen) != commentlen) {
- info("Unable to load comment.\n");
- return 0;
- }
- *(M.songtext+commentlen)=0;
- fix_string(M.songtext);
- expected_length+=commentlen;
- }
- else
- M.songtext=0;
-
- if(M.songtext && opt.verbose) {
- printf("\n--------------- Message: ---------------\n");
- tmp=0;
- while(tmp < commentlen) {
- printf("%.39s\n", &M.songtext[tmp]);
- tmp+=40;
- }
- printf("----------------------------------------\n");
- }
-
- return 1;
- }
-
- /* Filters out those effects not supported by Multitracker and adds the
- * balance-effect.
- */
-
- static void fix_effect(unsigned char *effect, unsigned char *arg)
- {
- switch(*effect) {
- case EFX_ARPEGGIO: /* Effects compatible with PT */
- case EFX_PORTAUP:
- case EFX_PORTADOWN:
- case EFX_PORTANOTE:
- case EFX_VIBRATO:
- case EFX_PORTANOTEVOLSLIDE:
- case EFX_VIBRATOVOLSLIDE:
- case EFX_TREMOLO:
- case EFX_UNUSED1:
- case EFX_SAMPLEOFFSET:
- case EFX_VOLSLIDE:
- case EFX_JUMP:
- case EFX_VOLUME:
- case EFX_BREAK:
- case EFX_FINEPORTAUP:
- case EFX_FINEPORTADOWN:
- case EFX_FINETUNE:
- case EFX_RETRIGGER:
- case EFX_FINEVOLSLIDEUP:
- case EFX_FINEVOLSLIDEDOWN:
- case EFX_NOTECUT:
- case EFX_NOTEDELAY:
- case EFX_PTSPEED:
- break;
-
- case EFX_UNUSED2: /* MTM: Balance */
- *effect=EFX_BALANCE;
- break;
- #if 0
- /* These effects are not supported by Multitracker */
- case EFX_FILTER:
- case EFX_GLISSANDO:
- case EFX_VIBWAVEFORM:
- case EFX_LOOP:
- case EFX_TREMWAVEFORM:
- case EFX_INVERTEDLOOP:
- #endif
- default:
- *effect=*arg=0;
- }
- }
-